package com.xiaoxie.system.service.impl;

import com.alibaba.druid.pool.DruidDataSource;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xiaoxie.common.constant.Constants;
import com.xiaoxie.common.enums.ReturnCode;
import com.xiaoxie.common.exception.BizException;
import com.xiaoxie.common.utils.AESUtils;
import com.xiaoxie.system.annatotion.SetDS;
import com.xiaoxie.system.config.DataSourceProperties;
import com.xiaoxie.system.datasource.DruidDataSourceBuilder;
import com.xiaoxie.system.datasource.DynamicDataSourceManager;
import com.xiaoxie.system.domain.Ds;
import com.xiaoxie.system.domain.dto.DsDto;
import com.xiaoxie.system.domain.dto.DsOptionDto;
import com.xiaoxie.system.domain.dto.DsQuery;
import com.xiaoxie.system.mapper.DsMapper;
import com.xiaoxie.system.service.DsService;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.*;

@Service
public class DsServiceImpl implements DsService {

    @Resource
    private DsMapper dsMapper;

    @Resource
    private DynamicDataSourceManager dynamicDataSourceManager;

    @Resource
    private DataSourceProperties dataSourceProperties;

    @Value("${crypto.secret}")
    private String secretKey;

    @SetDS("ds2")
    @Override
    public List<Ds> selectAll(String dsName) {
        return dsMapper.selectAll();
    }

    // 根据ds来生成数据源
    @Override
    public Object getDataSource(Ds ds) {
        dataSourceProperties.setUrl(ds.getUrl());
        dataSourceProperties.setUsername(ds.getUsername());
        dataSourceProperties.setPassword(ds.getPassword());
        return  DruidDataSourceBuilder.build(dataSourceProperties, null);
    }

    @Transactional
    @Override
    public boolean addDs(DsDto dsDto) {
        // 获取当前的 resolvedDataSources
        Map<Object, DataSource> currentResolvedDataSources = dynamicDataSourceManager.getResolvedDataSources();
        if (currentResolvedDataSources.containsKey(dsDto.getName())) {
            return false;
        }
        // 把dsDto转成ds
        Ds ds = new Ds();
        BeanUtils.copyProperties(dsDto, ds);
        ds.setCreateTime(new Date());
        dsMapper.insertSelective(ds);
        try {
            dataSourceProperties.setUrl(ds.getUrl());
            dataSourceProperties.setUsername(ds.getUsername());
            dataSourceProperties.setPassword(AESUtils.decrypt(ds.getPassword(), secretKey));
            DruidDataSource dataSource = DruidDataSourceBuilder.build(dataSourceProperties, null);
            // 创建一个新的可修改的 Map
            Map<Object, Object> newResolvedDataSources = new HashMap<>(currentResolvedDataSources);
            // 将新的数据源添加到新的 Map 中
            newResolvedDataSources.put(ds.getName(), dataSource);
            dynamicDataSourceManager.setTargetDataSources(newResolvedDataSources);
            dynamicDataSourceManager.afterPropertiesSet();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return true;
    }

    /**
     * 根据指定的数据源名称删除数据源
     * @param dsName
     */
    @Transactional
    @Override
    public void deleteDsByDsName(String dsName) {
        // 获取当前的 resolvedDataSources
        Map<Object, DataSource> currentResolvedDataSources = dynamicDataSourceManager.getResolvedDataSources();
        if (currentResolvedDataSources.containsKey(dsName)) {
            throw new BizException(ReturnCode.DATASOURCE_NOT_EXIST);
        }
        // 创建一个新的可修改的 Map
        Map<Object, Object> newResolvedDataSources = new HashMap<>(currentResolvedDataSources);
        newResolvedDataSources.remove(dsName);  // 移除指定的数据源
        dynamicDataSourceManager.setTargetDataSources(newResolvedDataSources);
        dynamicDataSourceManager.afterPropertiesSet();
        dsMapper.deleteByDsName(dsName);
    }

    @Transactional
    @Override
    public void batchDeleteDsById(List<Integer> idList) {
        for (Integer i : idList) {
            deleteDsById(i);
        }
    }

    @Override
    public List<DsOptionDto> getDsOptions() {
        return dsMapper.getDsOptions();
    }

    /**
     * 更新数据源
     * 注意：数据源的名称不可以更改
     * 先做删除再做新增动作
     * @param dsDto
     */
    @Transactional
    @Override
    public void updateDs(DsDto dsDto) {
        // deleteDsByDsName(dsDto.getName());
        deleteDsById(dsDto.getId());
        addDs(dsDto);
    }

    @Transactional
    @Override
    public void deleteDsById(Integer id) {
        // 获取当前的 resolvedDataSources
        Map<Object, DataSource> currentResolvedDataSources = dynamicDataSourceManager.getResolvedDataSources();
        Ds ds = dsMapper.selectByPrimaryKey(id);
        if (!currentResolvedDataSources.containsKey(ds.getName())) {
            throw new BizException(ReturnCode.DATASOURCE_NOT_EXIST);
        }
        // 创建一个新的可修改的 Map
        Map<Object, Object> newResolvedDataSources = new HashMap<>(currentResolvedDataSources);
        newResolvedDataSources.remove(ds.getName());  // 移除指定的数据源
        dynamicDataSourceManager.setTargetDataSources(newResolvedDataSources);
        dynamicDataSourceManager.afterPropertiesSet();
        dsMapper.deleteByPrimaryKey(id);
    }

    @Override
    public Set<Object>  getDataSources() {
        Map<Object, DataSource> resolvedDataSources = dynamicDataSourceManager.getResolvedDataSources();
        Set<Object> objects = resolvedDataSources.keySet();
        return objects;
    }

    @Override
    public PageInfo<Ds> selectByConditionWithPage(Integer pageNum, DsQuery ds) {
        PageHelper.startPage(pageNum, Constants.PAGE_SIZE);
        List<Ds> list =  dsMapper.selectDsByPage(ds);
        PageInfo<Ds> info = new PageInfo<>(list);
        return info;
    }

    @Override
    public Boolean checkName(String name) {
        List<Ds> list = dsMapper.selectDsByName(name);
        return !list.isEmpty();
    }

    @Override
    public Boolean testConnection(DsDto dsDto) {
        String password = AESUtils.decrypt(dsDto.getPassword(), secretKey);
        return testConnectDB(dsDto.getUrl(),dsDto.getUsername(), password);
    }

    @Override
    public Boolean updateCheckName(String name,Integer id) {
        List<Ds> list = dsMapper.selectDsByName(name);
        if (list == null || list.isEmpty()) {
            return false;
        }
        Ds ds = list.get(0);
        return !ds.getId().equals(id);
    }

    @Override
    public Ds getDsById(Integer id) {
        return dsMapper.selectByPrimaryKey(id);
    }

    /**
     * 测试数据库是否可连接
     * @param url
     * @param username
     * @param password
     * @return
     */
    private boolean testConnectDB(String url, String username, String password) {
        Connection connection = null;
        try{
            connection = DriverManager.getConnection(url, username, password);
            return connection != null && !connection.isClosed();
        } catch (Exception e) {
            return false;
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }
}
